package com.cares.common.dao.orm.hibernate;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.hql.ast.QueryTranslatorImpl;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.transform.ResultTransformer;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import cn.sh.cares.core.Constants;
import cn.sh.cares.core.pagination.OrderablePagination;
import cn.sh.cares.core.pagination.Pagination;
import cn.sh.cares.core.pagination.Sorter;
import cn.sh.cares.core.utils.StringUtils;
import cn.sh.cares.dao.DaoException;
import cn.sh.cares.dao.core.helper.SqlHelper;
import cn.sh.cares.dao.entity.BaseEntity;
import cn.sh.cares.dao.orm.hibernate.query.SafeDetachedCriteria;

/**
 * hibernate orm 实现
  * Copyright: Copyright (c) 2011  
  * Company: 上海民航华东凯亚系统集成有限公司  
  * @author: 
  * @version: 
  * @date：Nov 29, 2011 2:44:05 PM
 */
public class DefaultHibernateOrmExecution implements HibernateOrmExecution {

    private Log logger = LogFactory.getLog(getClass());

    //public DefaultHibernateOrmExecution(DataSource dataSource, SessionFactory sessionFactory) {
    public DefaultHibernateOrmExecution(SessionFactory sessionFactory) {
	this.hibernateTemplate = new HibernateTemplate();
	this.hibernateTemplate.setSessionFactory(sessionFactory);
    }
    
    private HibernateTemplate hibernateTemplate;
    
    public HibernateTemplate getHibernateTemplate() {
        return this.hibernateTemplate;
    }

    @Override
    public void clear() throws DaoException {
	try {
	    getHibernateTemplate().clear();
	} catch (DataAccessException dae) {
	    throw new DaoException("clear hibernate session error.", dae);
	} catch (RuntimeException e) {
	    throw new DaoException("clear hibernate session error.", e);
	}
    }

    @Override
    public void delete(BaseEntity entity) throws DaoException {
	if (entity == null) {
	    return;
	}
	try {
	    getHibernateTemplate().delete(entity);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Delete entity [" + entity + "] error.", dae);
//	    }
	    throw new DaoException("Delete entity [" + entity + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Delete entity [" + entity + "] error.", e);
//	    }
	    throw new DaoException("Delete entity [" + entity + "] error.", e);
	}
	if (logger.isInfoEnabled()) {
	    logger.info("Delete entity [" + entity + "]");
	}
    }

    @Override
    public void delete(BaseEntity[] entites) throws DaoException {
	if (ObjectUtils.isEmpty(entites)) {
	    return;
	}
	for (BaseEntity e : entites) {
	    delete(e);
	}
    }

    @Override
    public void delete(Collection<? extends BaseEntity> entites) throws DaoException {
	if (CollectionUtils.isEmpty(entites)) {
	    return;
	}
	delete((BaseEntity[]) entites.toArray(new BaseEntity[entites.size()]));
    }

    @Override
    public void delete(Class<? extends BaseEntity> clz, Serializable id) throws DaoException {
	delete(get(clz, id));
    }

    @Override
    public void flush() throws DaoException {
	try {
	    getHibernateTemplate().flush();
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("flush hibernate session error.", dae);
//	    }
	    throw new DaoException("flush hibernate session error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("flush hibernate session error.", e);
//	    }
	    throw new DaoException("flush hibernate session error.", e);
	}
    }

    @Override
    public <T> T get(Class<T> entityClass, Serializable id, LockMode lockMode) throws DaoException {
	return get(entityClass, id, lockMode, Constants.EMPTY_STRING_ARRAY);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(final Class<T> entityClass, final Serializable id, final LockMode lockMode, final String[] initFields) throws DaoException {
	if (id == null) {
	    return null;
	}
	try {
	    return (T) getHibernateTemplate().execute(new HibernateCallback() {
		@SuppressWarnings("deprecation")
		public Object doInHibernate(Session session) throws HibernateException, SQLException {
		    
		    //hibernate3.6, change to LockOptions
		    T t = (T) session.get(entityClass, id, lockMode);
		    if (t == null) {
			return null;
		    }
		    if (!ObjectUtils.isEmpty(initFields)) {
			initBeanFields(t, initFields);
		    }
		    return t;
		}
	    });
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Load entity [" + entityClass + "][" + lockMode + "] by id[" + id + "] error.", dae);
//	    }
	    throw new DaoException("Load entity [" + entityClass + "][" + lockMode + "] by id[" + id + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Load entity [" + entityClass + "][" + lockMode + "] by id[" + id + "] error.", e);
//	    }
	    throw new DaoException("Load entity [" + entityClass + "][" + lockMode + "] by id[" + id + "] error.", e);
	}
    }

    @Override
    public <T> T get(Class<T> entityClass, Serializable id) throws DaoException {
	return get(entityClass, id, Constants.EMPTY_STRING_ARRAY);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(final Class<T> entityClass, final Serializable id, final String[] initFields) throws DaoException {
	if (id == null) {
	    return null;
	}
	try {
	    return (T) getHibernateTemplate().execute(new HibernateCallback() {
		public Object doInHibernate(Session session) throws HibernateException, SQLException {
		    T t = (T) session.get(entityClass, id);
		    if (t == null) {
			return null;
		    }
		    if (!ObjectUtils.isEmpty(initFields)) {
			initBeanFields(t, initFields);
		    }
		    return t;
		}
	    });
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Load entity [" + entityClass + "] by id[" + id + "] error.", dae);
//	    }
	    throw new DaoException("Load entity [" + entityClass + "] by id[" + id + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Load entity [" + entityClass + "] by id[" + id + "] error.", e);
//	    }
	    throw new DaoException("Load entity [" + entityClass + "] by id[" + id + "] error.", e);
	}
    }

    @Override
    public BaseEntity merge(BaseEntity entity) throws DaoException {
	if (entity == null) {
	    return null;
	}
	try {
	    return (BaseEntity) getHibernateTemplate().merge(entity);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("merge entity [" + entity + "] error.", dae);
//	    }
	    throw new DaoException("merge entity [" + entity + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("merge entity [" + entity + "] error.", e);
//	    }
	    throw new DaoException("merge entity [" + entity + "] error.", e);
	}
    }

    @Override
    public BaseEntity merge(String entityName, BaseEntity entity) throws DaoException {
	if (entity == null) {
	    return null;
	}
	try {
	    return (BaseEntity) getHibernateTemplate().merge(entityName, entity);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("merge entity [" + entity + "] error.", dae);
//	    }
	    throw new DaoException("merge entity [" + entity + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("merge entity [" + entity + "] error.", e);
//	    }
	    throw new DaoException("merge entity [" + entity + "] error.", e);
	}
    }

    @Override
    public Serializable save(BaseEntity entity) throws DaoException {
	if (entity == null) {
	    return null;
	}
	try {
	    return getHibernateTemplate().save(entity);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Save entity [" + entity + "] error.", dae);
//	    }
	    throw new DaoException("Save entity [" + entity + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Save entity [" + entity + "] error.", e);
//	    }
	    throw new DaoException("Save entity [" + entity + "] error.", e);
	}
    }

    @Override
    public Serializable[] save(BaseEntity[] entites) throws DaoException {
	if (ObjectUtils.isEmpty(entites)) {
	    return Constants.EMPTY_SERIALIZABLE_ARRAY;
	}
	List<Serializable> ids = new ArrayList<Serializable>(entites.length);
	for (BaseEntity e : entites) {
	    ids.add(save(e));
	}
	return ids.toArray(new Serializable[entites.length]);
    }

    @Override
    public Serializable[] save(Collection<? extends BaseEntity> entites) throws DaoException {
	if (CollectionUtils.isEmpty(entites)) {
	    return Constants.EMPTY_SERIALIZABLE_ARRAY;
	}
	return save(entites.toArray(new BaseEntity[entites.size()]));
    }

    @Override
    public void saveOrUpdate(BaseEntity entity) throws DaoException {
	if (entity == null) {
	    return;
	}
	try {
	    getHibernateTemplate().saveOrUpdate(entity);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("SaveOrUpdate entity [" + entity + "] error.", dae);
//	    }
	    throw new DaoException("SaveOrUpdate entity [" + entity + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("SaveOrUpdate entity [" + entity + "] error.", e);
//	    }
	    throw new DaoException("SaveOrUpdate entity [" + entity + "] error.", e);
	}
    }

    @Override
    public void saveOrUpdate(BaseEntity[] entites) throws DaoException {
	if (ObjectUtils.isEmpty(entites)) {
	    return;
	}
	saveOrUpdate(Arrays.asList(entites));
    }

    @Override
    public void saveOrUpdate(Collection<? extends BaseEntity> entites) throws DaoException {
	if (CollectionUtils.isEmpty(entites)) {
	    return;
	}
	try {
	    getHibernateTemplate().saveOrUpdateAll(entites);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("SaveOrUpdate entites [" + entites + "] error.", dae);
//	    }
	    throw new DaoException("SaveOrUpdate entites [" + entites + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("SaveOrUpdate entites [" + entites + "] error.", e);
//	    }
	    throw new DaoException("SaveOrUpdate entites [" + entites + "] error.", e);
	}
    }

    @Override
    public void update(BaseEntity entity) throws DaoException {
	if (entity == null) {
	    return;
	}
	update(new BaseEntity[] { entity });
    }

    @Override
    public void update(BaseEntity[] entities) throws DaoException {
	if (ObjectUtils.isEmpty(entities)) {
	    return;
	}
	try {
	    for (BaseEntity entity : entities) {
		getHibernateTemplate().update(entity);
	    }
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Update [" + entities.length + "] entities " + Arrays.asList(entities) + " error.", dae);
//	    }
	    throw new DaoException("Update [" + entities.length + "] entities " + Arrays.asList(entities) + " error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Update [" + entities.length + "] entities " + Arrays.asList(entities) + " error.", e);
//	    }
	    throw new DaoException("Update [" + entities.length + "] entities " + Arrays.asList(entities) + " error.", e);
	}
	if (logger.isInfoEnabled()) {
	    logger.info("Update [" + entities.length + "] entities " + Arrays.asList(entities) + ".");
	}
    }

    @Override
    public void update(Collection<? extends BaseEntity> entites) throws DaoException {
	if (CollectionUtils.isEmpty(entites)) {
	    return;
	}
	update(entites.toArray(new BaseEntity[entites.size()]));
    }
    
    /**
     * 根据hql查询数据
     * 注：bug待修复，当params有enum类型的参数时，对统计总数有错误
     * 原因起于统计总数先把hql转成sql再执行统计总数。
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> queryForListByHql(Class<T> returnType, final String hql, final Object[] params, final Pagination pagination) throws DaoException {
	if (logger.isInfoEnabled()) {
	    logger.info("Query for list hql[" + hql + "], params[" + Arrays.asList(params) + "], pagination[" + pagination + "].");
	}
	try {
	    return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
		public Object doInHibernate(Session session) throws HibernateException, SQLException {
		    Query query = session.createQuery(hql);
		    applyParameters(query, params);
		    if (pagination != null && pagination.getTotalCount() < 1) {
			applyPaginationTotalCount(session.createSQLQuery(SqlHelper.getCountSql(
					convertHql2Sql(hql, (SessionFactoryImplementor) session.getSessionFactory()))),
				params, pagination);
		    }
		    if (pagination != null) {
			query.setFirstResult(pagination.getStartIndex());
			query.setMaxResults(pagination.getPageSize());
		    }
		    List<T> result = query.list();
		    return result == null ? Collections.EMPTY_LIST : result;
		}
	    });
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Query for list hql[" + hql + "], params[" + Arrays.asList(params) + "], pagination[" + pagination + "] error.", dae);
//	    }
	    throw new DaoException("Query for list hql[" + hql + "], params[" + Arrays.asList(params) + "], pagination[" + pagination + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Query for list hql[" + hql + "], params[" + Arrays.asList(params) + "], pagination[" + pagination + "] error.", e);
//	    }
	    throw new DaoException("Query for list hql[" + hql + "], params[" + Arrays.asList(params) + "], pagination[" + pagination + "] error.", e);
	}
    }

    @Override
    public <T> List<T> queryForListByHql(Class<T> returnType, String hql, Pagination pagination) throws DaoException {
	return queryForListByHql(returnType, hql, Constants.EMPTY_OBJECT_ARRAY, pagination);
    }

    @Override
    public <T> List<T> queryForListByHql(Class<T> returnType, String hql) throws DaoException {
	return queryForListByHql(returnType, hql, Constants.EMPTY_OBJECT_ARRAY, null);
    }
    
    @Override
    public <T> List<T> queryForListByHql(Class<T> returnType, String hql, Object[] params) throws DaoException {
	return queryForListByHql(returnType, hql, params, null);
    }
    
    @Override
    public <T> T queryForUniqueObjectByHql(Class<T> returnType, String hql, Object[] params, T defaultValue) throws DaoException {
	List<T> result = queryForListByHql(returnType, hql, params, null);
	return CollectionUtils.isEmpty(result) ? defaultValue : result.get(0);
    }
    
    @Override
    public <T> T queryForUniqueObjectByHql(Class<T> returnType, String hql, Object[] params) throws DaoException {
	return queryForUniqueObjectByHql(returnType, hql, params, null);
    }

    @Override
    public <T> T queryForUniqueObjectByHql(Class<T> returnType, String hql, T defaultValue) throws DaoException {
	return queryForUniqueObjectByHql(returnType, hql, Constants.EMPTY_OBJECT_ARRAY, defaultValue);
    }

    @Override
    public <T> T queryForUniqueObjectByHql(Class<T> returnType, String hql) throws DaoException {
	return queryForUniqueObjectByHql(returnType, hql, Constants.EMPTY_OBJECT_ARRAY, null);
    }

    @Override
    public int executeHql(final String hql, final Object... params) throws DaoException {
	if (logger.isInfoEnabled()) {
	    logger.info("Execute hql[" + hql + "], params[" + Arrays.asList(params) + "].");
	}
	try {
	    return ((Integer) getHibernateTemplate().execute(new HibernateCallback() {
		    public Object doInHibernate(Session session) throws HibernateException, SQLException {
			Query query = session.createQuery(hql);
			applyParameters(query, params);
			return Integer.valueOf(query.executeUpdate());
		    }
		})).intValue();
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Execute hql[" + hql + "], params[" + Arrays.asList(params) + "] error.", dae);
//	    }
	    throw new DaoException("Execute hql[" + hql + "], params[" + Arrays.asList(params) + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Execute hql[" + hql + "], params[" + Arrays.asList(params) + "] error.", e);
//	    }
	    throw new DaoException("Execute hql[" + hql + "], params[" + Arrays.asList(params) + "] error.", e);
	}
    }

    @Override
    public int executeHql(String hql) throws DaoException {
	return executeHql(hql, Constants.EMPTY_OBJECT_ARRAY);
    }

//    /**
//     * 抽取group projections，不考虑SQLProjection
//     * @param projection
//     * @return
//     */
//    private Projection extractGroupProjection(Projection projection) {
//	if (projection == null) {
//	    return null;
//	}
//	if (projection instanceof PropertyProjection) {
//	    PropertyProjection propertyProjection = (PropertyProjection) projection;
//	    if (propertyProjection.isGrouped()) {
//		return propertyProjection;
//	    }
//	} else if (projection instanceof ProjectionList) {
//	    ProjectionList projectionList = (ProjectionList) projection;
//	    if (projectionList.isGrouped()) {
//		ProjectionList result = Projections.projectionList();
//		for (int i = 0; i < projectionList.getLength(); i++) {
//		    Projection p = extractGroupProjection(projectionList.getProjection(i));
//		    if (p != null) {
//			result.add(p);
//		    }
//		}
//		return result;
//	    }
//	}
//	return null;
//    }
    
    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> queryForListByCriteria(final Class<T> returnType, 
	    final SafeDetachedCriteria safeDetachedCriteria, 
	    final OrderablePagination op) throws DaoException {
	final String[] initFields = safeDetachedCriteria.getInitProperties();
	if (logger.isInfoEnabled()) {
	    logger.info("Query by DetachedCriteria [" + safeDetachedCriteria + "], OrderablePagination [" + op + ", initFields " + Arrays.asList(initFields) + ".");
	}
	try {
	    return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
		public Object doInHibernate(Session session) throws HibernateException, SQLException {
		    CriteriaImpl criteria = (CriteriaImpl) safeDetachedCriteria.getExecutableCriteria(session);
		    if (op != null) {
			if (op.getTotalCount() < 1) {
			    //不支持group by投影的总数统计
			    Projection orginalProjection = criteria.getProjection();
			    ResultTransformer orginalResultTransformer = criteria.getResultTransformer();
			    Number count = (Number) criteria.setProjection(Projections.rowCount()).uniqueResult();
			    if (count != null) {
				// 兼容hibernate3.3和以前版本，之前返回Integer，之后返回Long
				op.setTotalCount(count.intValue());
			    }
			    criteria.setProjection(orginalProjection);
			    criteria.setResultTransformer(orginalResultTransformer);
			}
			criteria.setFirstResult(op.getStartIndex());
			criteria.setMaxResults(op.getPageSize());
			addCriteriaOrders(criteria, convertOrders(op.getSorters()));
			// 这儿有问题，没有还原detachedCriteria的ResultTransformer
			//criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		    }
		    List<T> results = criteria.list();
		    if (CollectionUtils.isEmpty(results)) {
			return Collections.emptyList();
		    }
		    if (ObjectUtils.isEmpty(initFields)) {
			return results;
		    }
		    for (T t : results) {
			initBeanFields(t, initFields);
		    }
		    return results;
		}
	    });
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Query by DetachedCriteria [" + safeDetachedCriteria + "], OrderablePagination [" + op + "] error.", dae);
//	    }
	    throw new DaoException("Query by DetachedCriteria [" + safeDetachedCriteria + "], OrderablePagination [" + op + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Query by DetachedCriteria [" + safeDetachedCriteria + "], OrderablePagination [" + op + "] error.", e);
//	    }
	    throw new DaoException("Query by DetachedCriteria [" + safeDetachedCriteria + "], OrderablePagination [" + op + "] error.", e);
	}
    }

    @Override
    public <T> List<T> queryForListByCriteria(Class<T> returnType, SafeDetachedCriteria safeDetachedCriteria) throws DaoException {
	return queryForListByCriteria(returnType, safeDetachedCriteria, null);
    }

    @Override
    public <T> T queryForUniqueObjectByCriteria(Class<T> returnType, 
	    final SafeDetachedCriteria safeDetachedCriteria, 
	    final T defaultValue) throws DaoException {
	if (logger.isInfoEnabled()) {
	    logger.info("Query by DetachedCriteria [" + safeDetachedCriteria + "], Class [" + 
		    returnType + "], defaultValue [" + defaultValue + "], initFields [" + Arrays.asList(safeDetachedCriteria.getInitProperties()) + "].");
	}
	try {
	    if (BaseEntity.class.isAssignableFrom(returnType)) {
		safeDetachedCriteria.setResultTransformer(Criteria.ROOT_ENTITY);		
	    }
	    List<T> resultList = queryForListByCriteria(returnType, safeDetachedCriteria, null);
	    if (CollectionUtils.isEmpty(resultList)) {
		return defaultValue;
	    }
	    T t = resultList.get(0);
	    if (t == null) {
		return defaultValue;
	    }
	    return t;
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Query by DetachedCriteria [" + safeDetachedCriteria + "], Class [" + returnType + "], defaultValue [" + defaultValue + "] error.", dae);
//	    }
	    throw new DaoException("Query by DetachedCriteria [" + safeDetachedCriteria + "], Class [" + returnType + "], defaultValue [" + defaultValue + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Query by DetachedCriteria [" + safeDetachedCriteria + "], Class [" + returnType + "], defaultValue [" + defaultValue + "] error.", e);
//	    }
	    throw new DaoException("Query by DetachedCriteria [" + safeDetachedCriteria + "], Class [" + returnType + "], defaultValue [" + defaultValue + "] error.", e);
	}
    }

    @Override
    public <T> T queryForUniqueObjectByCriteria(Class<T> returnType, SafeDetachedCriteria safeDetachedCriteria) throws DaoException {
	return queryForUniqueObjectByCriteria(returnType, safeDetachedCriteria, null);
    }

    @Override
    public void lock(Object entity, LockMode lockMode) throws DaoException {
	if (entity == null) {
	    return;
	}
	try {
	    getHibernateTemplate().lock(entity, lockMode);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Lock entity [" + entity + "] to [" + lockMode + "] error.", dae);
//	    }
	    throw new DaoException("Lock entity [" + entity + "] to [" + lockMode + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Lock entity [" + entity + "] to [" + lockMode + "] error.", e);
//	    }
	    throw new DaoException("Lock entity [" + entity + "] to [" + lockMode + "] error.", e);
	}	
    }

    @Override
    public void lock(String entityName, Object entity, LockMode lockMode) throws DaoException {
	if (entity == null) {
	    return;
	}
	try {
	    getHibernateTemplate().lock(entityName, entity, lockMode);
	} catch (DataAccessException dae) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Lock entity [" + entity + "][" + entityName + "] to [" + lockMode + "] error.", dae);
//	    }
	    throw new DaoException("Lock entity [" + entity + "][" + entityName + "] to [" + lockMode + "] error.", dae);
	} catch (RuntimeException e) {
//	    if (logger.isErrorEnabled()) {
//		logger.error("Lock entity [" + entity + "][" + entityName + "] to [" + lockMode + "] error.", e);
//	    }
	    throw new DaoException("Lock entity [" + entity + "][" + entityName + "] to [" + lockMode + "] error.", e);
	}
    }

    protected void addCriteriaOrders(Criteria criteria, List<Order> orders) {
	if (CollectionUtils.isEmpty(orders)) {
	    return;
	}
	for (Order order : orders) {
	    criteria.addOrder(order);
	}
    }
    
    /**
     * 把Sorter转换成hibernate的Order
     * @param sorters
     * @return
     */
    protected List<Order> convertOrders(Sorter[] sorters) {
	if (ObjectUtils.isEmpty(sorters)) {
	    return Collections.emptyList();
	}
	List<Order> orders = new ArrayList<Order>(sorters.length);
	for (Sorter sorter : sorters) {
	    orders.add(sorter.isAscending() ? Order.asc(sorter.getPropertyName()) : Order.desc(sorter.getPropertyName()));
	}
	return orders;
    }
    
    protected void applyParameters(Query query, Object[] params) {
	if (!ObjectUtils.isEmpty(params)) {
	    for (int i = 0; i < params.length; i++) {
		query.setParameter(i, params[i]);
	    }
	}
    }
    
    protected void applyPaginationTotalCount(Query countQuery, Object[] params, Pagination pagination) {
	applyParameters(countQuery, params);
	List<?> result = countQuery.list();
	if (CollectionUtils.isEmpty(result)) {
	    pagination.setTotalCount(0);	    
	} else {
	    pagination.setTotalCount(((Number) result.get(0)).intValue());
	}
    }
    /**
     * 根据给定的hql，生成统计总数的sql
     * @param hql
     * @param sfi
     * @return
     */
    protected String getCountSql(String hql, SessionFactoryImplementor sfi) {
	return SqlHelper.getCountSql(convertHql2Sql(hql, sfi));
    }
    
    /**
     * 根据给定的hql生成sql
     * @param hql
     * @param sfi
     * @return
     */
    protected String convertHql2Sql(String hql, SessionFactoryImplementor sfi) {
	QueryTranslatorImpl qtor = new QueryTranslatorImpl(hql, hql, Collections.EMPTY_MAP, sfi);
	qtor.compile(Collections.EMPTY_MAP, false);
	return qtor.getSQLString();
    }
    /**
     * 初始化bean里的字段
     * 对于一对一或多对一，可以无限管理初始化
     * 对于一对多，只能初始化到多这一层
     * @param bean
     * @param initFields
     */
    protected void initBeanFields(Object bean, String[] initFields) throws DaoException, IllegalArgumentException {
	if (bean == null || ObjectUtils.isEmpty(initFields)) {
	    return;
	}
	try {
	    for (String fieldName : initFields) {
		String[] splitFieldNames = StringUtils.tokenizeToStringArray(fieldName, "\\.");
		Object targetObject = bean;
		for (String splitFieldName : splitFieldNames) {
		    if (targetObject != null) {
			if (targetObject instanceof Collection<?>) {
			    for (Iterator<?> iter = ((Collection<?>) targetObject).iterator(); iter.hasNext();) {
				Hibernate.initialize(PropertyAccessorFactory.forBeanPropertyAccess(iter.next()).getPropertyValue(splitFieldName));
			    }
			    break;
			} else {
			    Hibernate.initialize(targetObject = PropertyAccessorFactory.forBeanPropertyAccess(targetObject).getPropertyValue(splitFieldName));
			}
		    }
		}
	    }
	} catch (HibernateException e) {
	    throw new DaoException("initialize error, fields is: " + Arrays.asList(initFields) + " and object is:" + bean, e);
	} catch (BeansException e) {
	    throw new IllegalArgumentException("get property value error, init fields is: " + Arrays.asList(initFields) + " and object is:" + bean, e);
	} catch (Exception e) {
//	    if (logger.isInfoEnabled()) {
//		logger.info("init bean fields:" + Arrays.asList(initFields) + " error of object: " + bean, e);
//	    }
	    throw new IllegalArgumentException("init bean fields:" + Arrays.asList(initFields) + " error of object: " + bean, e);
	}
    }
}
